package com.yunc.modules;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.yunc.base.aspect.AuthIgnore;
import com.yunc.base.queue.disruptor.DisruptorService;
import com.yunc.base.service.OkHttpService;
import com.yunc.base.service.RedisService;
import com.yunc.base.utils.R;
import com.yunc.base.utils.SnowFlake;
import com.yunc.base.utils.SysDictUtil;
import com.yunc.modules.shop.entity.ShopRandomCode;
import com.yunc.modules.shop.queue.MessageEvent;
import com.yunc.modules.shop.service.IShopRandomCodeService;
import com.yunc.modules.sys.entity.SysDictData;
import com.yunc.modules.sys.entity.SysUser;
import com.yunc.modules.sys.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author taocongcong
 * @create 2019-10-25 7:49
 */
@RestController
@RequestMapping("/test")
@Slf4j
public class TestController {

    private static final SnowFlake SNOW_FLAKE = new SnowFlake(9,10);

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisService redisService;
    @Autowired
    private OkHttpService okHttpService;
    @Autowired
    private DisruptorService disruptorService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IShopRandomCodeService shopRandomCodeService;
    // @Autowired
    // private AmqpTemplate amqpTemplate;
    // @Autowired
    // private RabbitMqAckSenderService rabbitMqAckSenderService;

    private volatile int n;

    /**
     * 当前用户
     * 自定义了hasPermission控制操作权限
     * and hasRole('sys:user:update')
     * hasRole,如果没有ROLE_就加上，所以所有带角色的需要加ROLE_
     */
    @GetMapping("/currentUser")
    @PreAuthorize("hasPermission(null, 'sys:user:save')")
    public R consumerDemo(Authentication authentication) {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (principal instanceof UserDetails) {
            System.out.println(principal);
        }
        SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        log.info(authentication.getName() + authentication.getPrincipal().toString());
        return R.ok(authentication.getName() + authentication.getPrincipal().toString());
    }

    @GetMapping("/testDict")
    public R testDict() {
        List<SysDictData> sysDictData = SysDictUtil.listDataByType("sys_user_sex");
        String userSex = SysDictUtil.getNameByValue("sys_user_sex", "1");
        String abs = new String("absddsddsddsdsdsdsdsdsdssasq2wqeweweewqeqeq").intern();
        String abc = new String("absddsddsddsdsdsdsdsdsdssasq2wqeweweewqeqeq").intern();
        if (abs == abc) {
            // 为什么是true，是因为在常量池中
            System.out.println("true");
        } else {
            System.out.println("false");
        }
        return R.ok().put("sysDictData", sysDictData);
    }

    @GetMapping("/testRedisson")
    public R testRedisson(){
        RLock rlock = redissonClient.getLock("redisson:lock:test");
        // 设置锁超时时间，防止异常造成死锁
        rlock.lock(10, TimeUnit.SECONDS);
        try {
            // 执行业务逻辑
            ++n;
        } catch(Exception e){
            e.printStackTrace();
        } finally{
            rlock.unlock();
        }
        return R.ok(String.valueOf(n));
    }

    @GetMapping("/testRedisSet")
    public R testRedisSet(){
        String itemId = "item" + RandomUtil.randomString(4);
        redisService.set(itemId, 200);
        log.info("时间：{}，增加itemId：{}，数量是{}", DateUtil.formatDateTime(DateUtil.date()), itemId, 200);
        return R.ok().put("name", itemId).put("itemCount", redisService.get(itemId));
    }

    @GetMapping("/testRedisDecrease")
    public R testRedisDecrease(String itemId){
        // 如果是限购如何操作，怎么将redis数据同步更新到数据库
        //1、限购的话在redis存储一个itemId和userid的表，当查询库存超过时避免存在
        //2、异步更新到数据库，存在时间偏差如何解决,前端轮询
        long decr = redisService.decr(itemId, 1);
        if (decr >= 0) {
            log.info("时间：{}，预定第{}个成功", DateUtil.formatDateTime(DateUtil.date()), decr);
            return R.ok("预定成功").put("itemCount", decr);
        } else {
            log.error("时间：{}，库存不足", DateUtil.formatDateTime(DateUtil.date()));
            long incr = redisService.incr(itemId, 1);
            // 需要下架该商品1、如果该商品有缓存则需要去除，2、将该商品数据库中状态修改，放入消息，或者使用多线程去处理
            return R.error("库存不足").put("itemCount", incr);
        }
    }

    @GetMapping("/testRedisGet")
    public R testRedisGet(String itemId){
        return R.ok().put("itemCount", redisService.get(itemId));
    }

    @GetMapping("/testOkHttp")
    public R testRedisGet(){
        String JISU_FLIGHT_CITY_URL = "http://api.jisuapi.com/flight/city";
        HashMap<String, String> params = new HashMap<>(1);
        // 应用APPKEY
        params.put("appkey", "8aae94724e864b25");
        String s = okHttpService.get(JISU_FLIGHT_CITY_URL, params);
        return R.ok(s);
    }

    @GetMapping("/testRabbitMqConsumer")
    public R testRabbitMqConsumer(){
        String content = "发送时间，Date:" + System.currentTimeMillis();
        //发送默认交换机对应的的队列kinson
        // amqpTemplate.convertAndSend("kinson", content);
        return R.ok();
    }

    private Object o = new Object();

    @GetMapping("/testRabbitMqConsumerAck")
    public R testRabbitMqConsumerAck(){
        synchronized (o) {
            //rabbitMqAckSenderService.send();
        }
        return R.ok();
    }

    @AuthIgnore
    @GetMapping("/apiSendRedisMsg")
    public R apiSendRedisMsg(){
        ShopRandomCode entity = new ShopRandomCode();
        // 采用雪花算法生成订单编号
        String code = String.valueOf(SNOW_FLAKE.nextId());
        entity.setCode(code);
        // redisService.convertAndSend("topic", entity);
        disruptorService.publishEvent(new MessageEvent());
        return R.ok();
    }

    /**
     * 测试悲观锁
     */
    @AuthIgnore
    @GetMapping("/send1")
    @Transactional
    public R send1(String id){
        ShopRandomCode entity = shopRandomCodeService.getByLock(id);
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        entity.setCode("1");
        shopRandomCodeService.updateById(entity);
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        SysUser sysUser = sysUserService.getById(1);
        System.out.println(sysUser);
        return R.ok();
    }

    @AuthIgnore
    @GetMapping("/send2")
    @Transactional
    public R send2(String id){
        SysUser sysUser = sysUserService.getById(1);
        System.out.println(sysUser);
        ShopRandomCode entity = shopRandomCodeService.getById(id);
        entity.setCode("2");
        shopRandomCodeService.updateById(entity);
        return R.ok();
    }

    public static void main(String[] args) {
        String abs = "absddsdd";
        String abc = "absddsdd1";
        abc = "absddsdd";
        if (abs == abc) {
            // 为什么是true，是因为在常量池中
            System.out.println("true");
        } else {
            System.out.println("false");
        }

        /*Integer i = 1000;
        int j = 1000;
        if (i == j) {
            // 比较，自动拆箱了
            System.out.println("true");
        } else {
            System.out.println("false");
        }*/
    }
}
